﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

[assembly:CLSCompliant(true)]
namespace SoftwareConsulting.Interfaces.BasicEntities
{
    /// <summary>
    /// Интерфейс иерархии
    /// </summary>
    public interface IHierarchy<T> : IUniqueChild, IEnumerable<T> where T : IUniqueChild
    {
        /// <summary>
        /// Возвращает количество листьев (концевых вершин) в иерархии
        /// </summary>
        int LeafsCount { get; }
        /// <summary>
        /// Возвращает максимальную глубину иерархии
        /// </summary>        
        /// <remarks>нумерация с самой иерархии (нулевой уровень)</remarks>
        int DeepestLevel { get; }
        /// <summary>
        /// Возвращает первый встреченный элемент по его тэгу (рекурсивно)
        /// </summary>
        /// <param name="needTag"></param>
        /// <returns></returns>
        T GetFirstItemByTag(object needTag);
        /// <summary>
        /// Блокирует иерархию от изменений
        /// </summary>
        /// <remarks>снять блокировку нельзя</remarks>
        void Block();
        /// <summary>
        /// Возвращает флаг блокировки иерархии
        /// </summary>
        bool IsBlocked { get; }        
        /// <summary>
        /// Возвращает глубину элемента
        /// </summary>
        int Deep { get; }
        /// <summary>
        /// Возвращает идентификаторы всех элементов иерархии, включая саму иерархию
        /// </summary>        
        List<Guid> IdsIncludingHierarchy { get; }
        /// <summary>
        /// Возвращает идентификаторы всех элементов иерархии
        /// </summary>        
        List<Guid> Ids { get; }
        /// <summary>
        /// Удаляет из иерархии все ее элементы
        /// </summary>
        void Clear();
        /// <summary>
        /// Возвращает флаг того, содержит ли данная иерархия указанный элемент (на верхнем уровне)
        /// </summary>
        /// <param name="needItem"></param>
        /// <returns></returns>
        bool Contains(T needItem);
        /// <summary>
        /// Возвращает флаг того, содержит ли данная иерархия указанный элемент с учетом флага рекурсивности
        /// </summary>
        /// <param name="needItem"></param>
        /// <returns></returns>
        bool Contains(T needItem, bool isRecursively);
        /// <summary>
        /// Возвращает флаг того, содержит ли данная иерархия указанный элемент (по идентификатору)
        /// </summary>
        /// <param name="needItemId"></param>
        /// <returns></returns>
        bool ContainsId(Guid needItemId);
        /// <summary>
        /// Возвращает количество элементов иерархии
        /// </summary>        
        int ItemsCount { get; }
        /// <summary>
        /// Возвращает элемент по его идентификатору с учетом флага рекурсивности
        /// </summary>
        /// <param name="needId"></param>
        /// <returns></returns>
        T GetItemById(Guid needId, bool recursively);
        /// <summary>
        /// Возвращает элемент по его идентификатору (нерекурсивно)
        /// </summary>
        /// <param name="needId"></param>
        /// <returns></returns>
        T GetItemById(Guid needId);
        /// <summary>
        /// Возвращает элемент по его идентификатору (нерекурсивно)
        /// </summary>
        /// <param name="needId"></param>
        /// <returns></returns>
        T this[Guid needId] { get; }
        /// <summary>
        /// Добавляет новый элемент в конец
        /// </summary>
        /// <param name="newItem"></param>
        /// <returns></returns>
        int Add(T newItem);
        /// <summary>
        /// Возвращает следующий элемент без учета иерархии
        /// </summary>
        T NextSiblingItem { get; }
        /// <summary>
        /// Удаляет указанный элемент
        /// </summary>
        /// <param name="itemToDelete"></param>
        /// <returns></returns>
        int Delete(T itemToDelete);
        /// <summary>
        /// Удаляет элемент по его идентификатору
        /// </summary>
        /// <param name="needId"></param>
        /// <returns></returns>
        int DeleteById(Guid needId);
        /// <summary>
        /// Возвращает позицию элемента в иерархии
        /// </summary>
        /// <param name="needItem"></param>
        /// <returns></returns>
        int GetPositionOfItem(T needItem);
        /// <summary>
        /// Возвращает элемент по его позиции (на текущем уровне иерархии)
        /// </summary>
        /// <param name="needPosition"></param>
        /// <returns></returns>
        T GetItemByPosition(int needPosition);
        /// <summary>
        /// Возвращает предыдущий элемент без учета иерархии
        /// </summary>
        T PreviousSiblingItem { get; }
        /// <summary>
        /// Возвращает глобальную позицию элемента (во всей иерархии)
        /// </summary>
        int GetGlobalPositionOfItem(T needItem);
        /// <summary>
        /// Возвращает элемент по его позиции (с учетом флага глобальности иерархии)
        /// </summary>
        /// <param name="needPosition"></param>
        T GetItemByPosition(int needPosition, bool isGlobalPosition);
        /// <summary>
        /// Вставляет новый элемент в указанную позицию
        /// </summary>
        /// <param name="newItem"></param>
        /// <param name="needPosition"></param>
        /// <returns>количество элементов в иерархии после вставки</returns>
        int Insert(T newItem, int needPosition);
        /// <summary>
        /// Удаляет элемент по его позиции
        /// </summary>
        /// <param name="needPosition"></param>
        /// <returns></returns>
        int DeleteByPosition(int needPosition);
        /// <summary>
        /// Меняет местами 2 элемента иерархии
        /// </summary>
        /// <param name="item1">позиция элемента 1</param>
        /// <param name="item2">позиция элемента 2</param>
        void SwapItems(T item1, T item2);
        /// <summary>
        /// Замена элемента в указанной позиции на новый элемент
        /// </summary>
        /// <param name="newItem"></param>
        /// <param name="needPosition"></param>
        void ChangeItemAtPosition(T newItem, int needPosition);
        /// <summary>
        /// Поднимает элемент иерархии выше на одну позицию
        /// </summary>
        /// <param name="needItem"></param>
        /// <returns>true - после поднятия еще есть куда двигаться, false - иначе</returns>
        bool UpItem(int curItemPosition);
        /// <summary>
        /// Опускает элемент иерархии ниже на одну позицию
        /// </summary>
        /// <param name="needItem"></param>
        /// <returns>true - после опускания еще есть куда двигаться, false - иначе</returns>
        bool DownItem(int curItemPosition);
    }
}
